cmake_minimum_required(VERSION 2.8.12)
# set the project name 
project(kasync) 
set(KASYNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
file(GLOB KASYNC_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
file(GLOB KASYNC_INCLUDE_FILES ${KASYNC_INCLUDE_DIR}/*.h)
message(STATUS "system is ${CMAKE_SYSTEM_NAME}")
#message(STATUS "current source dir is ${CMAKE_CURRENT_SOURCE_DIR}")
#message(STATUS "current binary dir is ${CMAKE_CURRENT_BINARY_DIR}")
option(KASYNC_TEST "build for test" OFF)
option(KSOCKET_SSL "enable tls/ssl support" ON)
option(ENABLE_KSSL_BIO "enable tls/ssl bio support" OFF)
option(ENABLE_FCONTEXT "enable fcontext" ON)
#option(OPENSSL_DIR "set openssl dir")
include(CheckIncludeFile)
include(CheckSymbolExists)

if (KSOCKET_SSL)
    message(STATUS "OPENSSL_DIR is ${OPENSSL_DIR}")
    if (NOT OPENSSL_DIR) 
	    include(FindOpenSSL)
	    if (NOT OPENSSL_FOUND)
			message(STATUS "cann't find openssl")
			set(KSOCKET_SSL OFF)
	    else()
			message(STATUS "build with tls/ssl support ${OPENSSL_INCLUDE_DIR}")
			list(APPEND KASYNC_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR})
			list(APPEND KASYNC_LIBS  OpenSSL::SSL OpenSSL::Crypto)
			set_target_properties(OpenSSL::SSL OpenSSL::Crypto PROPERTIES IMPORTED_GLOBAL True)
	    endif()
    else()
		list(APPEND KASYNC_INCLUDE_DIR ${OPENSSL_DIR}/include)
		list(APPEND KASYNC_LIBS ssl crypto)
    endif()
endif()

if (NOT KSOCKET_SSL)
    unset(ENABLE_KSSL_BIO)
endif()

if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android") 
    list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) 
    set(LINUX ON)
    option(LINUX_IOURING "enable io_uring")
    if (LINUX_IOURING)
        message(STATUS "linux use io_uring")
	list(APPEND KASYNC_LIBS uring)
    endif()
    if (CMAKE_SYSTEM_NAME MATCHES "Linux")
	    list(APPEND KASYNC_LIBS pthread)
	endif()
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
	set(FREEBSD ON)
	list(APPEND KASYNC_LIBS pthread)
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
	set(DARWIN ON)
        set(ENABLE_LIBUCONTEXT ON)
endif()

if (ENABLE_FCONTEXT)
    unset(ENABLE_LIBUCONTEXT)
    add_subdirectory(fcontext)
    list(APPEND KASYNC_LIBS boost_context)
endif()


if (CMAKE_SYSTEM_NAME MATCHES "Windows")
	list(APPEND KASYNC_LIBS ws2_32)
	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR})
	set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR})
else()
    include(CheckCSourceCompiles)
    if (NOT ENABLE_LIBUCONTEXT AND NOT ENABLE_FCONTEXT)
	    check_c_source_compiles(
		"#include<ucontext.h>
		int main(){
			ucontext_t ucp;
			getcontext(&ucp);
			}" HAVE_UCONTEXT)
	    if (NOT HAVE_UCONTEXT)
		    message(STATUS "NOT FOUND ucontext now auto turn on -DENABLE_LIBUCONTEXT=ON")
		    set(ENABLE_LIBUCONTEXT ON)
	    endif()
    endif()
    if (ENABLE_LIBUCONTEXT)
	    if (NOT LIBUCONTEXT_DIR)
		    set(LIBUCONTEXT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libucontext)
	    endif()
	    check_c_source_compiles(
		"#include<ucontext.h>
		typedef greg_t libucontext_greg_t;
		int main(){}" HAVE_UCONTEXT_GREG_T)
	    message(STATUS "now use libucontext dir ${LIBUCONTEXT_DIR}")
	    set(LIBUCONTEXT_LIBRARY ${LIBUCONTEXT_DIR}/libucontext.a)

	    if (HAVE_UCONTEXT_GREG_T)
		    set(FREESTANDING "no")
	    else()
		    set(FREESTANDING "yes")
	    endif()
	    message(STATUS "build libucontext.a FREESTANDING=${FREESTANDING}")
	    add_custom_target(libucontext.a ALL
		    COMMAND ${CMAKE_MAKE_PROGRAM} FREESTANDING=${FREESTANDING} libucontext.a 
		WORKING_DIRECTORY ${LIBUCONTEXT_DIR}
		COMMENT "build libucontext.a")
	    add_library(ucontext STATIC IMPORTED GLOBAL)
	    set_property(TARGET ucontext APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
	    set_target_properties(ucontext PROPERTIES IMPORTED_LOCATION_NOCONFIG "${LIBUCONTEXT_LIBRARY}")
	    add_dependencies(ucontext libucontext.a)
	    list(APPEND KASYNC_LIBS ucontext)
	    list(APPEND KASYNC_INCLUDE_DIR ${LIBUCONTEXT_DIR}/include)

    endif()
    check_symbol_exists(accept4 sys/socket.h HAVE_ACCEPT4)
    check_symbol_exists(memalign malloc.h HAVE_MEMALIGN)
    check_symbol_exists(setmntent mntent.h HAVE_SETMNTENT)
    check_symbol_exists(writev sys/uio.h HAVE_WRITEV)
    check_symbol_exists(readv sys/uio.h HAVE_READV)
endif()
    

if (GTEST_ROOT) 
    set(USE_CXX)
    set(CMAKE_CXX_STANDARD 14)
    #force use cxx
    file(GLOB KASYNC_FIBER_TEST_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/test/kfiter_test/*.cc)
    set(KASYNC_TEST_INCLUDE_DIR ${KASYNC_INCLUDE_DIR})
    list(APPEND KASYNC_FIBER_TEST_SOURCE_FILES ${KASYNC_SOURCE_FILES})
    #set(KASYNC_TEST_LIBS kasync)
    #set(KASYNC_TEST_LIBS_DIR ../../build)
    if (KSOCKET_SSL)
        include(FindOpenSSL)
        if (NOT OPENSSL_FOUND)
            message(FATAL_ERROR "cann't found ssl")
        endif() 
        list(APPEND KASYNC_TEST_LIBS  OpenSSL::SSL OpenSSL::Crypto)
        list(APPEND KASYNC_TEST_INCLUDE_DIR ${OPENSSL_INCLUDE_DIR}) 
    endif()
    if (CMAKE_SYSTEM_NAME MATCHES "Windows")
    #windows
        list(APPEND KASYNC_TEST_LIBS ws2_32)
    else()
        add_compile_options(-g)
        add_compile_options(-O0)
    endif()
    if (CMAKE_SYSTEM_NAME MATCHES "Linux") 
        #linux
        add_compile_options(-Wno-invalid-offsetof)
        if (LINUX_IOURING)
            list(APPEND KASYNC_TEST_LIBS uring)
        endif()
        list(APPEND KASYNC_TEST_LIBS pthread)
    elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
        list(APPEND KASYNC_TEST_LIBS pthread)
	
    endif()
    message(STATUS ${KASYNC_FIBER_TEST_SOURCE_FILES})
    list(APPEND KASYNC_FIBER_TEST_SOURCE_FILES ${GTEST_ROOT}/src/gtest-all.cc)
    list(APPEND KASYNC_TEST_INCLUDE_DIR ${GTEST_ROOT} ${GTEST_ROOT}/include)
    list(APPEND KASYNC_TEST_INCLUDE_DIR ${GTEST_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/test/) 
    message(STATUS "gtest include ${GTEST_INCLUDE_DIRS}")
    add_executable(kasync_fiber_test ${KASYNC_FIBER_TEST_SOURCE_FILES})
    target_include_directories(kasync_fiber_test PUBLIC ${KASYNC_TEST_INCLUDE_DIR})
    target_link_directories(kasync_fiber_test PUBLIC ${KASYNC_TEST_LIBS_DIR})
    target_link_libraries(kasync_fiber_test ${KASYNC_TEST_LIBS} ${KASYNC_LIBS})

endif()




configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/kasync_config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/kasync_config.h)
if (USE_CXX)
	message(STATUS "use c++ to build kasync libs")
	set_source_files_properties(${KASYNC_SOURCE_FILES} PROPERTIES LANGUAGE CXX)
endif()

get_directory_property(hasParent PARENT_DIRECTORY)
message(STATUS ${KASYNC_INCLUDE_DIR})
if(hasParent)
	set(KASYNC_INCLUDE_DIR ${KASYNC_INCLUDE_DIR} PARENT_SCOPE)
	set(KASYNC_LIBS ${KASYNC_LIBS} PARENT_SCOPE)
	set(KASYNC_SOURCE_FILES ${KASYNC_SOURCE_FILES} PARENT_SCOPE)
endif()
if (SHARED)
    message(STATUS "build as shared libary")
    set(WINDOWS_EXPORT_ALL_SYMBOLS ON)
    #set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
    add_library(kasync SHARED ${KASYNC_SOURCE_FILES} ${KASYNC_INCLUDE_FILES})
    target_link_libraries(kasync ${KASYNC_LIBS})
else()
    message(STATUS "build as static libary")
    add_library(kasync STATIC ${KASYNC_SOURCE_FILES} ${KASYNC_INCLUDE_FILES})
endif()
if (USE_CXX)
    set_target_properties(kasync PROPERTIES LINKER_LANGUAGE CXX)
endif()
target_include_directories(kasync PUBLIC ${KASYNC_INCLUDE_DIR})
add_executable(pingpang ${CMAKE_CURRENT_SOURCE_DIR}/example/pingpang.c)
target_link_libraries(pingpang kasync ${KASYNC_LIBS})

if (ENABLE_LIBUCONTEXT) 
    add_dependencies(kasync ucontext)
endif()

if (ENABLE_FCONTEXT)
    add_dependencies(kasync boost_context)
endif()
